package com.sys.group.controller;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sys.common.vo.Result;
import com.sys.function.STree;
import com.sys.group.entity.Edge;
import com.sys.group.entity.Node;
import com.sys.group.entity.Tree;
import com.sys.group.entity.User;
import com.sys.group.service.IEdgeService;
import com.sys.group.service.INodeService;
import com.sys.group.service.ITreeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author gyf
 * @since 2023-05-17
 */
@Api(tags = {"指标树管理接口"})
@RestController
@RequestMapping("/tree")
public class TreeController {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ITreeService treeService;

    @Autowired
    private IEdgeService edgeService;

    @Autowired
    private INodeService nodeService;

    @ApiOperation("树列表接口")
    @GetMapping("/list")
    public Result<Map<String, Object>> getTreeList(
            @RequestParam(value = "tname", required = false) String tname,
            @RequestParam(value = "time", required = false) String time,
            @RequestParam(value = "token", required = false) String token,
            @RequestParam("pageNo") Long pageNo,
            @RequestParam("pageSize") Long pageSize
    ) {
        Object obj = redisTemplate.opsForValue().get(token);
        User loginUser = JSON.parseObject(JSON.toJSONString(obj), User.class);
        Integer uid=loginUser.getId();

        LambdaQueryWrapper<Tree> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasLength(tname), Tree::getTname, tname);
        wrapper.like(StringUtils.hasLength(time), Tree::getTime, time);
        wrapper.eq(Tree::getUid, uid);
        wrapper.eq(Tree::getStatus, 0);
        wrapper.orderByDesc(Tree::getTid);

        Page<Tree> page = new Page<>(pageNo, pageSize);
        treeService.page(page, wrapper);

        Map<String, Object> data = new HashMap<>();
        data.put("total", page.getTotal());
        data.put("treeList", page.getRecords());

        return Result.success(data);
    }

    @ApiOperation("更新指标树接口")
    @PutMapping
    public Result<?> updateTree(@RequestBody Tree tree) {
        treeService.updateById(tree);
        return Result.success("修改指标树成功！");
    }




    public void create_tree(STree stree,Integer tid){

        List<Node> nodes=nodeService.getNodesById(stree.getId(),tid);
        List<Edge> edges=edgeService.getEdgesByParent(stree.getId(),tid);



        Node node=nodes.get(0);
        stree.setName(node.getName());
        stree.setLabel(node.getName());

        stree.setType(node.getType());
        stree.setWeight(node.getPercent());
        stree.setVal(node.getValue());
        stree.setParam(node.getOperator());

        for (Edge edge : edges) {
            //初始化赋值并插入当前节点的子节点列表
            STree child=new STree();
            child.setId(edge.getChild());
            child.setPid(edge.getParent());
            child.setExpand(true);
            child.setRoot(false);
            List<STree> children=stree.getChildren();
            children.add(child);
            //递归调用该方法，不断向下生成该树
            create_tree(child,tid);

            stree.setChildren(children);
        }
    }
    @ApiOperation("根据id获取树信息接口")
    @GetMapping("/{tid}")
    public Result<Map<String, Object>> getTreeById(@PathVariable("tid") Integer tid) {
        //stree为根节点，接下来读取数据库中点和边信息，将其转换为stree中的数据，并转换成json发送回前端
        STree stree = new STree();
        Tree tree = treeService.getById(tid);

        //读取树名
        stree.setTreename(tree.getTname());
        //根节点的id为0，前端已固定，进入递归向下的算法，将整个树构造出来
        stree.setId(0);
        stree.setExpand(true);
        stree.setRoot(true);
        create_tree(stree,tid);
//        System.out.println(stree);
        Map<String, Object> data = new HashMap<>();
        data.put("tree", stree);

        return Result.success(data);
    }


    @ApiOperation("删除指标树接口")
    @DeleteMapping("/{tid}")
    public Result<Tree> deleteTreeById(@PathVariable("tid") Integer tid) {
        Tree tree = treeService.getById(tid);
        tree.setStatus(1);
        treeService.updateById(tree);
        return Result.success("删除指标树成功！");
    }

    //判断是否存在列不存在与给的数据中
    boolean notfind=false;
    boolean notop=false;
    String notname="";
    public String getLeafValueByName(List<values> values, String name){
        for (values value : values){
            if (value.getName().equals(name)){
                return value.getValue();
            }
        }
        return null;
    }

    //递归计算树
    public Double calculate(STree stree,List<values> values){
        //出现了未找到的叶子节点
        if (notfind || notop) return 1.0;
        if (stree.getChildren().size()!=0) {

            if(stree.getParam()==null || stree.getParam().equals("")){
                notop=true;
                notname=stree.getName();
                System.out.println("没有操作符："+stree);
            }else {
                System.out.println("testNull: " + stree);
                if (Objects.equals(stree.getParam(), "+")) {
                    double value = 0;
                    for (STree child : stree.getChildren()) {
                        value += calculate(child, values);
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "-")) {
                    double value = 0;
                    //判断是否为第一个被减数
                    int place = 0;
                    for (STree child : stree.getChildren()) {
                        if (place == 0) {
                            value += calculate(child, values);
                        } else {
                            value -= calculate(child, values);
                        }
                        place++;
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "*")) {
                    double value = 1;
                    for (STree child : stree.getChildren()) {
                        value *= calculate(child, values);
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "/")) {
                    double value = 1;
                    //判断是否为第一个被除数
                    int place = 0;
                    for (STree child : stree.getChildren()) {
                        if (place == 0) {
                            value *= calculate(child, values);
                        } else {
                            value /= calculate(child, values);
                        }
                        place++;
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "max")) {
                    double value = 0;
                    //判断是否为第一个比较数
                    int place = 0;
                    for (STree child : stree.getChildren()) {
                        double temp = calculate(child, values);
                        if (place == 0) {
                            value = temp;
                        } else {
                            if (value < temp) {
                                value = temp;
                            }
                        }
                        place++;
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "min")) {
                    double value = 0;
                    //判断是否为第一个比较数
                    int place = 0;
                    for (STree child : stree.getChildren()) {
                        double temp = calculate(child, values);
                        if (place == 0) {
                            value = temp;
                        } else {
                            if (value > temp) {
                                value = temp;
                            }
                        }
                        place++;
                    }
                    stree.setVal(value);
                } else if (Objects.equals(stree.getParam(), "avg")) {
                    double value = 0;
                    for (STree child : stree.getChildren()) {
                        value += calculate(child, values) / stree.getChildren().size();
                    }
                    stree.setVal(value);
                }
            }
        }else {
            //查找叶子节点的数据，未找到则设置notfind
            String value=getLeafValueByName(values, stree.getName());
            if (value==null){
                notfind=true;
                notname=stree.getName();
            }else {
                stree.setVal(Double.valueOf(value));
            }

        }

        return stree.getVal()*stree.getWeight();
    }


    @ApiOperation("根据id和值计算指标树")
    @PostMapping("/cal")
    public Result<Map<String, Object>> calTree(
            @RequestBody RequestData requestData) throws CloneNotSupportedException {

        int tid = requestData.getTid();
        List<values> leafs = requestData.getValues();


        notfind=false;
        notop=false;
        notname="";
        //stree为根节点，接下来读取数据库中点和边信息，将其转换为stree中的数据，并转换成json发送回前端
        STree stree = new STree();
        Tree tree = treeService.getById(tid);

        //读取树名
        stree.setTreename(tree.getTname());
        //根节点的id为0，前端已固定，进入递归向下的算法，将整个树构造出来
        stree.setId(0);
        stree.setExpand(true);
        stree.setRoot(true);
        create_tree(stree,tid);

        STree temp=(STree) stree.clone();
        //开始计算数据
        calculate(stree,leafs);

        Map<String, Object> returndata = new HashMap<>();
        //存在未找到叶子节点信息，返回原来的树信息;否则成功计算
        if (notfind){
            returndata.put("message", "导入失败，缺少叶子节点: "+notname+" 信息。");
            returndata.put("tree",temp);
        } else if (notop) {
            returndata.put("message", "导入失败，"+notname+" 缺少算子信息。");
            returndata.put("tree",temp);
        } else {
            returndata.put("message", "导入成功!");
            returndata.put("tree",stree);
        }

        return Result.success(returndata);
    }
}

@Data
class RequestData {
    private int tid;
    private List<values> values;
}
class values {
    private String name;
    private String value;

    // 构造函数、getter和setter方法

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
